import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, QAction, QSystemTrayIcon, \
    QPushButton, QListWidget, QTextEdit, QMessageBox
from PyQt5.QtCore import QTimer, QObject, pyqtSignal, QThread, Qt, QEventLoop
from PyQt5.QtGui import QIcon

from apscheduler.schedulers.qt import QtScheduler
from PyQt5.QtCore import pyqtSlot

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

from SQLiteHelper import SQLiteHelper
from datetime import datetime

sender_email = 'tramper8@163.com'
sender_password = 'EARZDBZBTRAMPERDHYVCCYF'

job_table = 'jobs'

class SchedulerSingal(QObject):
    reminder_signal = pyqtSignal(str)

    def __init__(self, window):
        super(SchedulerSingal, self).__init__()
        self.window = window

    def schedule_reminder(self, reminder_text):
        self.reminder_signal.emit(reminder_text)        
        
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        
        # 显示提示框信息
        self.show_messagebox = True

        self.scheduler = QtScheduler()
        self.schedulerReminderSignal = SchedulerSingal(self)
        
        self.schedulerReminderSignal.reminder_signal.connect(self.handle_finished)

        self.setWindowTitle("定时提醒应用")
        
        # 标记变量，默认不允许关闭应用程序
        self.allow_close = False

        # 创建主窗口部件
        main_widget = QWidget()

        # 创建操作区域
        operation_layout = QVBoxLayout()
        operation_widget = QWidget()
        operation_widget.setLayout(operation_layout)

        label_time = QLabel("提醒时间（Cron表达式）：")
        self.entry_time = QLineEdit()
        self.entry_time.setText('*/1 * * * *')

        label_text = QLabel("提醒事件内容：")
        self.entry_text = QLineEdit()
        self.entry_text.setText('该喝水了')

        button_set = QPushButton("添加提醒")
        button_set.clicked.connect(self.add_reminder)

        operation_layout.addWidget(label_time)
        operation_layout.addWidget(self.entry_time)
        operation_layout.addWidget(label_text)
        operation_layout.addWidget(self.entry_text)
        operation_layout.addWidget(button_set)

        # 创建提醒列表区域
        reminder_list_widget = QWidget()
        reminder_list_layout = QVBoxLayout()
        reminder_list_widget.setLayout(reminder_list_layout)

        self.reminder_list = QListWidget()
        
        toggle_button = QPushButton("禁用/启用")
        toggle_button.clicked.connect(self.toggle_reminder)

        reminder_list_layout.addWidget(self.reminder_list)
        reminder_list_layout.addWidget(toggle_button)

        # 创建日志区域
        log_widget = QWidget()
        log_layout = QVBoxLayout()
        log_widget.setLayout(log_layout)

        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)

        log_layout.addWidget(self.log_text)

        # 创建主窗口布局
        main_layout = QHBoxLayout()
        main_layout.addWidget(operation_widget)
        main_layout.addWidget(reminder_list_widget)

        main_widget.setLayout(main_layout)

        # 创建主窗口总布局
        total_layout = QVBoxLayout()
        total_layout.addWidget(main_widget)
        total_layout.addWidget(log_widget)

        central_widget = QWidget()
        central_widget.setLayout(total_layout)
        self.setCentralWidget(central_widget)
        # 初始化数据库
        self.init_database()
        
        # 初始化提醒数据
        self.init_reminder_list()

        # 启动定时任务
        self.scheduler.start()
        
        # 初始化托盘菜单
        self.init_tray_menu()
        
    def init_database(self):
        self.dbHelper = SQLiteHelper("reminder.db")
        self.dbHelper.create_table(job_table, "id INTEGER PRIMARY KEY AUTOINCREMENT, cron VARCHAR, message TEXT, disabled TINYINT, created_at DATETIME, updated_at DATETIME")
        
    def init_reminder_list(self):
        rows = self.dbHelper.select_data(job_table)
        print(rows)
        for row in rows:
            print(row)
            self.init_reminder(row[0], row[1], row[2])

    def init_tray_menu(self):
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon('reminder.png'))  # 设置图标

        # 创建菜单项
        open_action = QAction("Open", self)
        exit_action = QAction("Exit", self)
        open_action.triggered.connect(self.show_window)
        exit_action.triggered.connect(self.exit_application)

        # 创建菜单
        tray_menu = QMenu(self)
        tray_menu.addAction(open_action)
        tray_menu.addSeparator()
        tray_menu.addAction(exit_action)

        # 将菜单设置到托盘图标
        self.tray_icon.setContextMenu(tray_menu)

        # 双击托盘图标时显示窗口
        self.tray_icon.activated.connect(self.tray_activated)
        
    def show_window(self):
        self.show()

    def tray_activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.show()

    def exit_application(self):
        self.hide()
        QApplication.quit()
        
    def add_tray_menu(self):
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon('avatar.jpg'))  # 设置图标

        # 创建菜单项
        open_action = QAction("Open", self)
        exit_action = QAction("Exit", self)
        open_action.triggered.connect(self.show_window)
        exit_action.triggered.connect(self.exit_application)

        # 创建菜单
        tray_menu = QMenu(self)
        tray_menu.addAction(open_action)
        tray_menu.addSeparator()
        tray_menu.addAction(exit_action)

        # 将菜单设置到托盘图标
        self.tray_icon.setContextMenu(tray_menu)

        # 双击托盘图标时显示窗口
        self.tray_icon.activated.connect(self.tray_activated)

    def add_reminder(self):
        reminder_time = self.entry_time.text()
        reminder_text = self.entry_text.text()

        # 设定提醒任务
        try:
            # 检查表达式是否正确
            cron_fields = reminder_time.split()
            if len(cron_fields) != 5:
                raise ValueError("Cron 表达式格式错误！")
                
            # 检查是否有相同时间的任务
            for job in self.scheduler.get_jobs():
                if job.next_run_time is not None and job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') == reminder_time:
                    self.scheduler.remove_job(job_id=job.id)
                    self.log_text.append(f"已禁用提醒：{job.args[0]}")
                    break

            self.scheduler.add_job(
                self.show_reminder, 'cron',
                second='0', minute=cron_fields[0], hour=cron_fields[1], day=cron_fields[2], month=cron_fields[3], day_of_week=cron_fields[4],
                args=[reminder_text]
            )
            
            field = ('cron', 'message', 'disabled', 'created_at', 'updated_at')
            data = (reminder_time, reminder_text, 0, datetime.now(), datetime.now())
            new_job_id = self.dbHelper.insert_data(job_table, field, data)
            
            print(self.scheduler.get_jobs())
        except Exception as e:
            QMessageBox.warning(self, "错误", str(e))
            return

        self.reminder_list.addItem(f"{new_job_id} - {reminder_time} - {reminder_text}")
        self.entry_time.clear()
        self.entry_text.clear()
        self.log_text.append("提醒已添加！")
        
    def init_reminder(self, reminder_id, reminder_time, reminder_text):
        # 设定提醒任务
        try:
            # 检查表达式是否正确
            cron_fields = reminder_time.split()
            if len(cron_fields) != 5:
                raise ValueError("Cron 表达式格式错误！")
                
            # 检查是否有相同时间的任务
            for job in self.scheduler.get_jobs():
                if job.next_run_time is not None and job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') == reminder_time:
                    self.scheduler.remove_job(job_id=job.id)
                    self.log_text.append(f"已禁用提醒：{job.args[0]}")
                    break
            print(str(reminder_id) + '--------' + reminder_time + '--------' +reminder_text)
            self.scheduler.add_job(
                self.show_reminder, 'cron',
                second='0', minute=cron_fields[0], hour=cron_fields[1], day=cron_fields[2], month=cron_fields[3], day_of_week=cron_fields[4],
                args=[reminder_text]
            )
        except Exception as e:
            # QMessageBox.warning(self, "错误", str(e))
            print('异常了：' + str(e))
            return

        self.reminder_list.addItem(f"{reminder_id} - {reminder_time} - {reminder_text}")
        self.log_text.append("提醒已初始化！")

    def show_reminder(self, reminder_text):
        # print('show_remindershow_remindershow_remindershow_reminder')
        self.schedulerReminderSignal.schedule_reminder(reminder_text)
        
    @pyqtSlot(str)
    def handle_finished(self, reminder_text):
        if self.show_messagebox :
            self.show_messagebox = False
            event_loop = QEventLoop()
            reply = QMessageBox.question(self, '提示', reminder_text, QMessageBox.Yes)
            # 暂时不发邮件了
            # self.send_email(sender_email, sender_password, '791672300@qq.com', 'test', 'Hello world')
            if reply == QMessageBox.Yes:
                # event_loop.quit()
                print('Yes')
            else:
                # event_loop.quit()
                print('No')
                
            self.show_messagebox = True
            event_loop.exec_()
            event = event_loop.childEvent()
            if event:
                event.ignore()
        
        self.log_text.append(reminder_text)

    def toggle_reminder(self):
        selected_item = self.reminder_list.currentItem()
        if not selected_item:
            QMessageBox.warning(self, "警告", "请选择要禁用/启用的提醒！")
            return

        selected_text = selected_item.text()
        reminder_id = selected_text.split(" - ")[0]
        reminder_time = selected_text.split(" - ")[1]
        reminder_text = selected_text.split(" - ")[2]

        print('job id: ' + reminder_id + ', time: ' + reminder_time +', message: '+ reminder_text)
        for job in self.scheduler.get_jobs():
            if job.args[0] == reminder_text:
                if job.next_run_time is not None:
                    print('job is active, will be removed/paused.')
                    # 禁用任务
                    job.pause()
                    # self.scheduler.remove_job(job_id=job.id)
                    self.log_text.append(f"已禁用提醒：{reminder_text}")
                    self.dbHelper.update_data(job_table, "disabled", 1, "id=" + reminder_id)
                    QMessageBox.information(self, "成功", "提醒已禁用！")
                else:
                    print('job is inactive, will be added.')
                    # 检查表达式是否正确
                    cron_fields = reminder_time.split()
                    if len(cron_fields) != 5:
                        raise ValueError("Cron 表达式格式错误！")
                    # 启用任务
                    job.resume()    
                    # print(reminder_time +','+job.next_run_time.strftime('%Y-%m-%d %H:%M:%S')+','+'启用')
                    # self.scheduler.remove_job(job_id=job.id)
                    
                    # self.scheduler.add_job(self.show_reminder, 'cron', second='0', minute=cron_fields[0], hour=cron_fields[1], 
                    #    day=cron_fields[2], month=cron_fields[3], day_of_week=cron_fields[4], args=[reminder_text], id=job.id)
                    self.log_text.append(f"已启用提醒：{reminder_text}")
                    self.dbHelper.update_data(job_table, "disabled", 0, "id=" + reminder_id)
                    QMessageBox.information(self, "成功", "提醒已启用！")
                break
                    

    def closeEvent(self, event):
        print(self.allow_close)
        # 关闭时停止定时任务
        if not self.allow_close:
            event.ignore()  # 忽略窗口关闭事件，防止应用程序被关闭
            self.hide()    # 隐藏窗口而非关闭窗口

        # self.scheduler.shutdown()
           
    def send_email(self, sender_email, sender_password, receiver_email, subject, message):
        # 创建一个MIMEMultipart对象
        msg = MIMEMultipart()
        msg['From'] = sender_email
        msg['To'] = receiver_email
        msg['Subject'] = subject

        # 添加正文
        msg.attach(MIMEText(message, 'plain'))

        try:
            # 创建SMTP对象
            server = smtplib.SMTP('smtp.163.com', 25)

            # 登录到发件人邮箱
            server.login(sender_email, sender_password)

            # 发送邮件
            server.sendmail(sender_email, receiver_email, msg.as_string())

            print('邮件发送成功')
        except Exception as e:
            print('邮件发送失败:', str(e))
        finally:
            # 关闭SMTP连接
            server.quit()

def start_app():
    app = QApplication(sys.argv)
    # window = MainWindow()
    # window.show()
    
    # 初始化托盘应用
    tray_app = MainWindow()
    tray_app.setGeometry(100, 100, 500, 400)

    # 显示托盘图标
    tray_app.tray_icon.show()
    
    sys.exit(app.exec_())

if __name__ == '__main__':
    start_app()